package com.leeoohoo.base;

import com.leeoohoo.error.BizError;
import com.oohoo.spacestationspringbootstarter.config.SpringUtils;
import com.oohoo.spacestationspringbootstarter.dto.query.Butler;
import com.oohoo.spacestationspringbootstarter.dto.query.DTO;
import com.oohoo.spacestationspringbootstarter.dto.query.EPage;
import com.oohoo.spacestationspringbootstarter.dto.query.EQ;
import com.oohoo.spacestationspringbootstarter.dto.query.annotation.Deleted;
import com.oohoo.spacestationspringbootstarter.dto.query.lambda.ClassUtils;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import org.springframework.beans.BeanUtils;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @Description:
 * @Author: lei.d.li@capgemini.com
 * @CreateTime: 2023/1/31
 */
public interface BaseService<T, ID> {

    default void save(DTO dto) {
        Method getId = BeanUtils.findDeclaredMethod(dto.getClass(), "getId");
        try {
            if (Objects.isNull(getId)) {
                this.getButler().insert(dto);
                return;
            }
            Long id = (Long) getId.invoke(dto);
            if (Objects.isNull(id)) {
                this.getButler().insert(dto);
            } else {
                T t = this.getT();
                BeanUtils.copyProperties(dto, t);
                this.getButler().update(EQ.update(t.getClass())
                        .set(t).updateById(t));
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizError("保存发生异常");
        }
    }

    default void deleteById(ID id) {
        this.getRepository().deleteById(id);
    }

    default void deleteAllById(List<ID> idList) {
        this.getRepository().deleteAllById(idList);
    }

    default void logicDelete(ID id) {
        EntityTransaction transaction = this.getButler().getEm().getTransaction();
        transaction.begin();
        try {
            Optional<T> byId = this.getRepository().findById(id);
            byId.ifPresent(t -> {
                ArrayList<Field> fileds = ClassUtils.getFileds(t.getClass());
                Optional<Field> first = fileds.stream().filter(f -> {
                    Deleted deleted = f.getDeclaredAnnotation(Deleted.class);
                    return null != deleted;
                }).findFirst();
                if (first.isPresent()) {
                    try {
                        Field field = first.get();
                        field.setAccessible(true);
                        field.set(byId.get(), 1);
                    } catch (Exception exception) {
                        throw new RuntimeException("逻辑删除时，变更默认值发生异常:" + exception.getMessage());
                    }
                } else {
                    throw new RuntimeException("该对象不支持逻辑删除");
                }
                this.getButler().update(EQ.update(t.getClass())
                        .set(t).updateById(t));
                transaction.commit();
            });
        } catch (Exception e) {
            e.printStackTrace();
            transaction.rollback();
            throw new RuntimeException("批量逻辑删除是发生异常");
        }


    }

    default T get(ID id) {
        T one = (T) this.getButler().findOne(
                EQ.find(getT().getClass())
                        .select(this.getT().getClass())
                        .findById(id),
                this.getT().getClass()
        );
        return one;
    }


    default <PD extends PageDTO> EPage<PD> page(PD dto) {
        return this.getButler().findPage(dto, dto.getPageNum(), dto.getPageSize());
    }

    default <PD extends PageDTO> List<PD> list(PD dto) {
        return this.getButler().findList(dto);
    }


    T getT();


    default SimpleJpaRepository<T, ID> getRepository() {
        EntityManagerFactory factory = SpringUtils.getBean(EntityManagerFactory.class);
        EntityManager entityManager = factory.createEntityManager();
        return new SimpleJpaRepository(getT().getClass(), entityManager);
    }

    default Butler getButler() {
        return SpringUtils.getBean(Butler.class);
    }


}
